package com.alibaba.citrus.cr.order.open.api.facade.service;

import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.lock.RedisLock;
import com.alibaba.citrus.cr.order.open.api.facade.common.model.WmsOrderMessageDTO;
import com.alibaba.citrus.cr.order.open.api.facade.common.model.WmsOutBoundMessage;
import com.alibaba.citrus.cr.order.open.api.facade.common.until.CheckUtil;
import com.alibaba.citrus.cr.order.open.api.facade.model.TransferOrder;
import com.alibaba.citrus.cr.order.open.api.facade.service.calculate.CalculateCommonUtil;
import com.alibaba.citrus.cr.order.open.api.facade.service.calculate.TransferCalculateHandlerFactory;
import com.alibaba.citrus.cr.order.open.api.facade.service.calculate.TransferCalculateQuantityHandler;
import com.alibaba.citrus.cr.order.open.api.facade.service.fulfillmentorder.TransferFulfillmentOrderHandler;
import com.alibaba.citrus.cr.order.open.api.facade.transfer.TransferCenterCommonService;
import com.alibaba.cloud.retail.wms.api.model.orders.common.WarehousingOrderDTO;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.contants.BcOrderConstants;
import com.epoch.app.mninventorycenter.outboundmessageprocess.dto.*;
import com.epoch.app.mninventorycenter.outboundmessageprocess.service.OutBoundMessageProcessService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author yifei
 * @since 2024/1/15
 */
@Service
@Primary
public class OutBoundMessageProcessServiceImpl implements OutBoundMessageProcessService {
    private static Log log = Log.getLogger(OutBoundMessageProcessServiceImpl.class);

    @Resource
    private TransferCenterCommonService transferCenterCommonService;

    @Resource
    private List<TransferFulfillmentOrderHandler> transferFulfillmentOrderHandlerList;

    @Resource
    private TransferCalculateHandlerFactory transferCalculateHandlerFactory;


    @Override
    @FacadeInvoker(remark = "接收出入库单创建消息")
    public Result<String> receiveOutBoundMessage(ReceiveOutBoundMessageRequest receiveRequest) {
        log.info("receiveOutBoundMessage_request:{}", JSON.toJSONString(receiveRequest));
        boolean accept = CalculateCommonUtil.accept(receiveRequest.getMessage());
        if (!accept) {
            log.info("receiveOutBoundMessage_no_need_to_process");
            return Result.success("no need to process message");
        }
        WmsOutBoundMessage wmsOutBoundMessage = JSON.parseObject(receiveRequest.getMessage(), WmsOutBoundMessage.class);
        if (wmsOutBoundMessage == null || StringUtils.isBlank(wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId())) {
            log.error("receiveOutBoundMessage_error");
            return Result.success("bizOrderId null");
        }
        String bizOrderId = wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId();
        //请求幂等
        try (RedisLock lock = new RedisLock(BcOrderConstants.REDIS_CACHE_CODE(), "receiveOutBound" + bizOrderId, 10 * 1000, 10 * 5000)) {
            if (!lock.lock()) {
                return Result.fail("", "不能重复提交");
            }
            TransferOrder orderInfo = transferCenterCommonService.getTransferOrderInfo(bizOrderId);
            if (orderInfo == null || CollectionUtils.isEmpty(orderInfo.getDetailList())) {
                log.info("receiveOutBoundMessage_orderInfo_null");
                return Result.success("orderInfo null");
            }
            List<WarehousingOrderDTO> warehousingOrderList = transferCenterCommonService.queryWmsOrder(bizOrderId);
            if (CollectionUtils.isEmpty(warehousingOrderList)) {
                log.info("receiveOutBoundMessage_warehousingOrderList_null");
                return Result.success("warehousingOrderList null");
            }
            /*// key:业务单据行号，value:明细对应数量的累加
            Map<String, BigDecimal> allocateOutMap = new HashMap<>();
            Map<String, BigDecimal> allocateInMap = new HashMap<>();
            for (WarehousingOrderDTO order : warehousingOrderList) {
                List<com.alibaba.cloud.retail.wms.api.model.orders.common.WmsOrderDetailDTO> orderDetailList = order.getWmsOrderDetailList();
                if (CollectionUtils.isEmpty(orderDetailList)) {
                    continue;
                }
                if (CalculateCommonUtil.ALLOCATE_OUT.equals(order.getMainOrderType())) {
                    // 计算累计待出库、待收货数量
                    CalculateCommonUtil.calculateQuantity(orderDetailList, allocateOutMap);
                } else if (CalculateCommonUtil.ALLOCATE_IN.equals(order.getMainOrderType())) {
                    CalculateCommonUtil.calculateQuantity(orderDetailList, allocateInMap);
                }
            }

            Map<String, SubFeaturesRequest> currentFeatures = new HashMap<>();
            for (TransferSubOrder subOrder : orderInfo.getDetailList()) {
                SubFeaturesRequest request = new SubFeaturesRequest();
                Map<String, String> subBizFeaturesToUpdate = new HashMap<>(2);
                // 累计待出库数量
                BigDecimal waitOutBoundQty = allocateOutMap.get(subOrder.getLineNo());
                subBizFeaturesToUpdate.put(CalculateCommonUtil.CUMULATIVE_WAIT_OUT_BOUND_QUANTITY, CalculateCommonUtil.convertToString(waitOutBoundQty));
                // 累计待收货数量
                BigDecimal waitReceivedQty = allocateInMap.get(subOrder.getLineNo());
                subBizFeaturesToUpdate.put(CalculateCommonUtil.CUMULATIVE_WAIT_RECEIVED_QUANTITY, CalculateCommonUtil.convertToString(waitReceivedQty));
                request.setSubBizFeaturesToUpdate(subBizFeaturesToUpdate);
                currentFeatures.put(subOrder.getLineNo(), request);
            }
            // 更新当前调拨单
            transferCenterCommonService.updateTransferSubBizFeatures(wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId(), currentFeatures);*/
            TransferCalculateQuantityHandler calculateHandler = transferCalculateHandlerFactory.getTransferCalculateHandler(orderInfo.getTransferOrderType());
            if (calculateHandler == null) {
                log.error("receiveOutBoundMessage_calculateHandler_null");
                return Result.success("calculateHandler null");
            }
            calculateHandler.handle(warehousingOrderList, wmsOutBoundMessage, orderInfo);
            return Result.success("success");
        }
    }

    /**
     * 出入库单结果确认消息
     * <p>
     * 1、出库单或入库单上的业务单据号对应的调拨单如果是仓间调拨单，只需要更新当前调拨单地累计已出库数量、累计待出库数量、累计已收货数量、累计待收货数量（出库和收货互斥）
     * 2、出库单或入库单上的业务单据号对应的调拨单如果是计划调拨单，除了上述需要更新的字段之外，需要额外更新对应的计划调拨预报单地累计已出库数量、累计待出库数量、累计已收货数量、累计待收货数量（出库和收货互斥）
     * 3、出库单或入库单上的业务单据号对应的调拨单如果是货场提货单，除了上述需要更新的字段之外，需要额外更新关联的调拨单以及关联调拨单对应的计划调拨预报单地累计已提货数量和累计已完成数量（出库和收货互斥）
     *
     * @param receiveRequest 入参
     * @return 结果
     */
    @Override
    @FacadeInvoker(remark = "接收出入库单结果确认消息")
    public Result<String> receiveOutBoundConfirmMessage(ReceiveOutBoundConfirmMessageRequest receiveRequest) {
        log.info("receiveOutBoundConfirmMessage_request:{}", JSON.toJSONString(receiveRequest));
        boolean accept = CalculateCommonUtil.accept(receiveRequest.getMessage());
        if (!accept) {
            log.info("receiveOutBoundConfirmMessage_no_need_to_process");
            return Result.success("no need to process message");
        }
        WmsOutBoundMessage wmsOutBoundMessage = JSON.parseObject(receiveRequest.getMessage(), WmsOutBoundMessage.class);
        if (wmsOutBoundMessage == null || StringUtils.isBlank(wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId())) {
            log.error("receiveOutBoundConfirmMessage_error");
            return Result.success("bizOrderId null");
        }
        String bizOrderId = wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId();
        //请求幂等
        try (RedisLock lock = new RedisLock(BcOrderConstants.REDIS_CACHE_CODE(), "receiveOutBoundConfirm" + bizOrderId, 10 * 1000, 10 * 5000)) {
            if (!lock.lock()) {
                return Result.fail("", "不能重复提交");
            }
            TransferOrder orderInfo = transferCenterCommonService.getTransferOrderInfo(bizOrderId);
            log.info("receiveOutBoundConfirmMessage_orderInfo:{}", JSON.toJSONString(orderInfo));
            if (orderInfo == null || CollectionUtils.isEmpty(orderInfo.getDetailList())) {
                log.info("receiveOutBoundConfirmMessage_orderInfo_null");
                return Result.success("orderInfo null");
            }
            if (CalculateCommonUtil.checkFulfillmentType(orderInfo)) {
                log.info("receiveOutBoundConfirmMessage_fulfillmentType_no_match");
                return Result.success("fulfillmentType no match");
            }
            List<WarehousingOrderDTO> warehousingOrderList = transferCenterCommonService.queryWmsOrder(bizOrderId);
            log.info("receiveOutBoundConfirmMessage_warehousingOrderList:{}", JSON.toJSONString(warehousingOrderList));
            if (CollectionUtils.isEmpty(warehousingOrderList)) {
                log.info("receiveOutBoundConfirmMessage_warehousingOrderList_null");
                return Result.success("warehousingOrderList null");
            }

            TransferCalculateQuantityHandler calculateHandler = transferCalculateHandlerFactory.getTransferCalculateHandler(orderInfo.getTransferOrderType());
            if (calculateHandler == null) {
                log.error("receiveOutBoundConfirmMessage_calculateHandler_null");
                return Result.success("calculateHandler null");
            }
            boolean retryFlag = Boolean.FALSE;
            try {
                calculateHandler.handle(warehousingOrderList, wmsOutBoundMessage, orderInfo);
            } catch (Exception e) {
                log.error("receiveOutBoundConfirmMessage_calculateHandler_handle_error:", e);
                retryFlag = Boolean.TRUE;
            }
            //是否货场调拨单,是的话要走创建逆向履约单
            Nullable.stream(transferFulfillmentOrderHandlerList).forEach(handler -> {
                if (CalculateCommonUtil.ALLOCATE_OUT.equals(wmsOutBoundMessage.getWmsOrderDTO().getMainOrderType())
                        && handler.support(orderInfo)){
                    handler.handler(warehousingOrderList,orderInfo,wmsOutBoundMessage);
                }
            });
            if (retryFlag) {
                return Result.fail("", "数量计算失败,请重试");
            }
            return Result.success("success");
        }
    }

    /**
     * 接收出入库创建更新消息
     */
    @Override
    @FacadeInvoker(remark = "接收出入库创建更新消息")
    public Result<String> receiveOutBoundUpdateMessage(ReceiveOutBoundUpdateMessageRequest receiveRequest) {
        log.info("receiveOutBoundUpdateMessage_request:{}", JSON.toJSONString(receiveRequest));
        boolean accept = CalculateCommonUtil.accept(receiveRequest.getMessage());
        if (!accept) {
            log.info("receiveOutBoundUpdateMessage_no_need_to_process");
            return Result.success("no need to process message");
        }
        WmsOutBoundMessage wmsOutBoundMessage = JSON.parseObject(receiveRequest.getMessage(), WmsOutBoundMessage.class);
        if (wmsOutBoundMessage == null || StringUtils.isBlank(wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId())) {
            log.error("receiveOutBoundUpdateMessage_error");
            return Result.success("bizOrderId null");
        }
        String bizOrderId = wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId();
        //请求幂等
        try (RedisLock lock = new RedisLock(BcOrderConstants.REDIS_CACHE_CODE(), "receiveOutBoundUpdate" + bizOrderId, 10 * 1000, 10 * 5000)) {
            if (!lock.lock()) {
                return Result.fail("", "不能重复提交");
            }
            TransferOrder orderInfo = transferCenterCommonService.getTransferOrderInfo(bizOrderId);
            if (orderInfo == null || CollectionUtils.isEmpty(orderInfo.getDetailList())) {
                log.info("receiveOutBoundUpdateMessage_orderInfo_null");
                return Result.success("orderInfo null");
            }
            List<WarehousingOrderDTO> warehousingOrderList = transferCenterCommonService.queryWmsOrder(bizOrderId);
            if (CollectionUtils.isEmpty(warehousingOrderList)) {
                log.info("receiveOutBoundUpdateMessage_warehousingOrderList_null");
                return Result.success("warehousingOrderList null");
            }
            TransferCalculateQuantityHandler calculateHandler = transferCalculateHandlerFactory.getTransferCalculateHandler(orderInfo.getTransferOrderType());
            if (calculateHandler == null) {
                log.error("receiveOutBoundUpdateMessage_calculateHandler_null");
                return Result.success("calculateHandler null");
            }
            calculateHandler.handle(warehousingOrderList, wmsOutBoundMessage, orderInfo);
            return Result.success("success");
        }
    }

    /**
     * 接收出入库完成消息
     * 创建货场提货单专用
     */
    @Override
    @FacadeInvoker(remark = "接收出入库完成消息")
    public Result<String> receiveOutBoundCompleteMessage(ReceiveOutBoundCompleteMessageRequest request) {
        log.info("receiveOutBoundCompleteMessage_request:{}", JSON.toJSONString(request));
        boolean accept = CalculateCommonUtil.checkAllocateInType(request.getMessage());
        if (!accept) {
            log.info("receiveOutBoundCompleteMessage_no_need_to_process");
            return Result.success("no need to process message");
        }
        WmsOutBoundMessage wmsOutBoundMessage = JSON.parseObject(request.getMessage(), WmsOutBoundMessage.class);
        if (wmsOutBoundMessage == null || StringUtils.isBlank(wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId())
                || StringUtils.isBlank(wmsOutBoundMessage.getWmsOrderDTO().getWarehousingOrderId())) {
            log.error("receiveOutBoundCompleteMessage_error");
            return Result.success("bizOrderId null");
        }
        String bizOrderId = wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId();
        String wmsOrderId = wmsOutBoundMessage.getWmsOrderDTO().getWarehousingOrderId();
        //请求幂等
        try (RedisLock lock = new RedisLock(BcOrderConstants.REDIS_CACHE_CODE(), "receiveOutBoundComplete" + wmsOrderId, 10 * 1000, 10 * 5000)) {
            if (!lock.lock()) {
                return Result.fail("", "不能重复提交");
            }
            TransferOrder orderInfo = transferCenterCommonService.getTransferOrderInfo(bizOrderId);
            log.info("receiveOutBoundComplete_orderInfo:{}", JSON.toJSONString(orderInfo));
            if (orderInfo == null || CollectionUtils.isEmpty(orderInfo.getDetailList())) {
                log.info("receiveOutBoundComplete_orderInfo_null");
                return Result.success("orderInfo null");
            }
            // 非计划调拨单、非铁运海运、没有货场仓不处理
            if (!CheckUtil.checkCreateFreightYardTransfer(orderInfo)) {
                log.info("receiveOutBoundComplete_no_need_create_freightYard_transfer");
                return Result.success("no need create freightYard transfer");
            }
            // 幂等校验,是否通过入库单创建过货场提货单
            TransferOrder transferOrderInfo = transferCenterCommonService.getTransferOrderInfoByThirdAllocateOrderId(wmsOrderId);
            if (transferOrderInfo != null) {
                log.info("receiveOutBoundComplete_idempotent_success");
                return Result.success("receiveOutBoundComplete_idempotent_success");
            }
            List<WarehousingOrderDTO> warehousingOrderList = transferCenterCommonService.queryWmsOrderByWmsOrderId(wmsOrderId);
            log.info("receiveOutBoundComplete_warehousingOrderList:{}", JSON.toJSONString(warehousingOrderList));
            if (CollectionUtils.isEmpty(warehousingOrderList)) {
                log.info("receiveOutBoundComplete_warehousingOrderList_null");
                return Result.success("warehousingOrderList null");
            }
            Boolean success = transferCenterCommonService.createFreightYardTransfer(wmsOutBoundMessage.getWmsOrderDTO(), warehousingOrderList, orderInfo);
            if (success) {
                return Result.success("success");
            }
            return Result.fail("", "货场提货单创建失败");
        }
    }

    /**
     * 接收出入库消息(包括多个tag)
     *
     */
    @Override
    @FacadeInvoker(remark = "接收出入库消息(包括多个tag)")
    public Result<String> receiveOutBoundQueueMessage(ReceiveOutBoundQueueMessageRequest request) {
        log.info("receiveOutBoundQueueMessage_request:{}", JSON.toJSONString(request));
        if (StringUtils.isBlank(request.getMessage())) {
            log.info("receiveOutBoundQueueMessage_request_no_need_to_process");
            return Result.success("no need to process message");
        }
        WmsOutBoundMessage wmsOutBoundMessage = JSON.parseObject(request.getMessage(), WmsOutBoundMessage.class);
        if (StringUtils.isBlank(wmsOutBoundMessage.getTag())) {
            return Result.success("no need to process message");
        }
        Result<String> result = Result.success("success");
        switch (wmsOutBoundMessage.getTag()) {
            case "OUT_BOUND_ORDER_CREATE" :
                ReceiveOutBoundMessageRequest createMessageRequest = new ReceiveOutBoundMessageRequest();
                createMessageRequest.setMessage(request.getMessage());
                log.info("receiveOutBoundQueueMessage_createMessageRequest:{}", JSON.toJSONString(createMessageRequest));
                result = this.receiveOutBoundMessage(createMessageRequest);
                break;
            case "ORDER_DETAIL_UPDATE" :
                ReceiveOutBoundUpdateMessageRequest updateMessageRequest = new ReceiveOutBoundUpdateMessageRequest();
                updateMessageRequest.setMessage(request.getMessage());
                log.info("receiveOutBoundQueueMessage_updateMessageRequest:{}", JSON.toJSONString(updateMessageRequest));
                result = this.receiveOutBoundUpdateMessage(updateMessageRequest);
                break;
            case "OUT_BOUND_ORDER_CONFIRM" :
                ReceiveOutBoundConfirmMessageRequest confirmMessageRequest = new ReceiveOutBoundConfirmMessageRequest();
                confirmMessageRequest.setMessage(request.getMessage());
                log.info("receiveOutBoundQueueMessage_confirmMessageRequest:{}", JSON.toJSONString(confirmMessageRequest));
                result = this.receiveOutBoundConfirmMessage(confirmMessageRequest);
                break;
            case "OUT_BOUND_ORDER_REVERSE" :
                ReceiveOutBoundReverseMessageRequest reverseMessageRequest = new ReceiveOutBoundReverseMessageRequest();
                reverseMessageRequest.setMessage(request.getMessage());
                result = this.receiveOutBoundReverseMessage(reverseMessageRequest);
            default:
                break;
        }
        return result;
    }

    /**
     * 接收出入库冲销消息
     *
     */
    @Override
    @FacadeInvoker(remark = "接收出入库冲销消息")
    public Result<String> receiveOutBoundReverseMessage(ReceiveOutBoundReverseMessageRequest request) {
        log.info("receiveOutBoundReverseMessage_request:{}", JSON.toJSONString(request));
        boolean accept = CalculateCommonUtil.accept(request.getMessage());
        if (!accept) {
            log.info("receiveOutBoundReverseMessage_no_need_to_process");
            return Result.success("no need to process message");
        }
        WmsOutBoundMessage wmsOutBoundMessage = JSON.parseObject(request.getMessage(), WmsOutBoundMessage.class);
        if (wmsOutBoundMessage == null || StringUtils.isBlank(wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId())) {
            log.error("receiveOutBoundReverseMessage_error");
            return Result.success("bizOrderId null");
        }
        if (!"BC".equals(wmsOutBoundMessage.getOs())) {
            log.info("receiveOutBoundReverseMessage_os_null");
            return Result.success("os null");
        }
        // 冲销取反
        WmsOrderMessageDTO wmsOrderDTO = wmsOutBoundMessage.getWmsOrderDTO();
        Integer mainOrderType = wmsOrderDTO.getMainOrderType();
        if (CalculateCommonUtil.ALLOCATE_IN.equals(mainOrderType)) {
            wmsOrderDTO.setMainOrderType(CalculateCommonUtil.ALLOCATE_OUT);
        } else if (CalculateCommonUtil.ALLOCATE_OUT.equals(mainOrderType)) {
            wmsOrderDTO.setMainOrderType(CalculateCommonUtil.ALLOCATE_IN);
        }

        String bizOrderId = wmsOutBoundMessage.getWmsOrderDTO().getBizOrderId();
        //请求幂等
        try (RedisLock lock = new RedisLock(BcOrderConstants.REDIS_CACHE_CODE(), "receiveOutBoundReverse" + bizOrderId, 10 * 1000, 10 * 5000)) {
            if (!lock.lock()) {
                return Result.fail("", "不能重复提交");
            }
            TransferOrder orderInfo = transferCenterCommonService.getTransferOrderInfo(bizOrderId);
            log.info("receiveOutBoundReverseMessage_orderInfo:{}", JSON.toJSONString(orderInfo));
            if (orderInfo == null || CollectionUtils.isEmpty(orderInfo.getDetailList())) {
                log.info("receiveOutBoundReverseMessage_orderInfo_null");
                return Result.success("orderInfo null");
            }
            if (CalculateCommonUtil.checkFulfillmentType(orderInfo)) {
                log.info("receiveOutBoundReverseMessage_fulfillmentType_no_match");
                return Result.success("fulfillmentType no match");
            }
            List<WarehousingOrderDTO> warehousingOrderList = transferCenterCommonService.queryWmsOrder(bizOrderId);
            log.info("receiveOutBoundReverseMessage_warehousingOrderList:{}", JSON.toJSONString(warehousingOrderList));
            if (CollectionUtils.isEmpty(warehousingOrderList)) {
                log.info("receiveOutBoundReverseMessage_warehousingOrderList_null");
                return Result.success("warehousingOrderList null");
            }

            TransferCalculateQuantityHandler calculateHandler = transferCalculateHandlerFactory.getTransferCalculateHandler(orderInfo.getTransferOrderType());
            if (calculateHandler == null) {
                log.error("receiveOutBoundReverseMessage_calculateHandler_null");
                return Result.success("calculateHandler null");
            }
            log.info("receiveOutBoundReverseMessage_wmsOutBoundMessage:{}", JSON.toJSONString(wmsOutBoundMessage));
            calculateHandler.handle(warehousingOrderList, wmsOutBoundMessage, orderInfo);
            // 取消履约单
            transferCenterCommonService.cancelFulfillmentOrder(wmsOutBoundMessage.getReverseOriginWmsOrderId());
            return Result.success("success");
        }
    }
}
